package cn.edu.zut.hhr.utils;

import com.alibaba.fastjson.JSON;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.boot.configurationprocessor.json.JSONException;
import org.springframework.boot.configurationprocessor.json.JSONObject;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

@Slf4j
@Data
@Component
public class ElasticSearchUtil {

    public static final String DEFAULT_INDEX = "elastic_search";

    @Resource(name = "restHighLevelClient")
    private RestHighLevelClient client;
    private static String index = DEFAULT_INDEX;

    /**
     * 创建索引
     *
     * @param index
     * @return
     */
    public boolean createIndex(String index) {
        CreateIndexRequest createIndexRequest = new CreateIndexRequest(index);
        CreateIndexResponse indexresponse = null;
        try {
            indexresponse = client.indices().create(createIndexRequest, RequestOptions.DEFAULT);
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.info("执行建立成功？" + indexresponse.isAcknowledged());

        return indexresponse.isAcknowledged();
    }

    /**
     * 删除索引
     *
     * @param index
     * @return
     */
    public boolean deleteIndex(String index) throws IOException {
        if (!isIndexExist(index)) {
            log.info("Index is not exits!");
        }
        DeleteIndexRequest dRequest = new DeleteIndexRequest(index);
        return client.indices().delete(dRequest, RequestOptions.DEFAULT).isAcknowledged();
    }

    /**
     * 判断索引是否存在
     *
     * @param index
     * @return
     */
    public boolean isIndexExist(String index) throws IOException {
        GetIndexRequest getIndexRequest = new GetIndexRequest(index);
        return client.indices().exists(getIndexRequest, RequestOptions.DEFAULT);
    }

    /**
     * 数据添加，正定ID
     *
     * @param jsonString 要增加的数据
     * @param index      索引，类似数据库
     * @return
     */
    public String addData(String jsonString, String index, String id) throws IOException {

        IndexRequest indexRequest = new IndexRequest(index);
        indexRequest.id(id).source(jsonString, XContentType.JSON);
        IndexResponse indexResponse = client.index(indexRequest, RequestOptions.DEFAULT);
        return indexResponse.toString();
    }


    /**
     * 批量插入数据
     */

    public void batchInsertData(List<JSONObject> list, String index) throws JSONException {
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout("30s");
        for (JSONObject jsonObject : list) {
            /**
             * 更改器方法,记得每次新的
             */
            bulkRequest.add(new IndexRequest(index).id((String) jsonObject.get("id")).source(jsonObject, XContentType.JSON));
        }
    }

    /**
     * 通过ID删除数据
     *
     * @param index 索引，类似数据库
     * @param id    数据ID
     */
    public void deleteDataById(String index, String id) throws IOException {

        DeleteResponse response = client.delete(new DeleteRequest(index, id), RequestOptions.DEFAULT);
    }

    /**
     * 通过ID 更新数据
     *
     * @param jsonObject 要增加的数据
     * @param index      索引，类似数据库
     * @param id         数据ID
     * @return
     */
    public void updateDataById(JSONObject jsonObject, String index, String id) throws IOException {

        UpdateRequest updateRequest = new UpdateRequest();

        updateRequest.index(index).id(id).doc(jsonObject);

        client.update(updateRequest, RequestOptions.DEFAULT);

    }

    /**
     * 通过ID获取数据
     *
     * @param index 索引，类似数据库
     * @param id    数据ID
     * @return
     */
    public Map<String, Object> searchDataById(String index, String id) throws IOException {
        GetResponse getResponse = client.get(new GetRequest(index, id), RequestOptions.DEFAULT);
        return getResponse.getSource();
    }

    /**
     * @param name  按什么字段进行查询,一般是name(和参数name不是一个,参数name是字段名,这个name是商品名)
     * @param val   值,空格分割
     * @param index 所要查询的索引
     */
    public String searchData(String name, String val, String index) throws IOException {
        SearchRequest searchRequest = new SearchRequest(index);
        /**
         * 构建查询条件,高亮,并且按score降序,同时设置所查属性高亮
         */
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery(name, val);
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field(name);
        sourceBuilder.highlighter(highlightBuilder);
        sourceBuilder.sort("_score", SortOrder.DESC);
        sourceBuilder.query(matchQueryBuilder);

        searchRequest.source(sourceBuilder);

        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        SearchHit[] searchHits = searchResponse.getHits().getHits();
        List<Map> list = new ArrayList<>();
        for(SearchHit searchHit: searchHits){
            list.add(searchHit.getSourceAsMap());
        }
        return JSON.toJSONString(Arrays.toString(list.toArray()));
    }

    public String getIndex() {
        return index;
    }

    public void setIndex(String index) {
        ElasticSearchUtil.index = index;
    }
}